package com.webchat.user.service.relation;

import com.webchat.common.enums.AccountRelationStatusEnum;
import com.webchat.common.enums.AccountRelationTypeEnum;
import com.webchat.common.enums.ChatMessageTypeEnum;
import com.webchat.common.enums.RedisKeyEnum;
import com.webchat.common.enums.messagequeue.MessageBroadChannelEnum;
import com.webchat.common.service.RedisService;
import com.webchat.common.service.messagequeue.producer.MessageQueueProducer;
import com.webchat.common.util.DateUtils;
import com.webchat.common.util.JsonUtil;
import com.webchat.domain.vo.dto.WaitConfirmRelationBaseDTO;
import com.webchat.domain.vo.request.mess.MessageNotifyVO;
import com.webchat.domain.vo.response.UserBaseResponseInfoVO;
import com.webchat.domain.vo.response.WaitConfirmUserResponseVO;
import com.webchat.user.repository.entity.AccountRelationEntity;
import com.webchat.user.service.UserService;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;


@Service
public class User2UserAccountRelationService extends AbstractAccountRelationService {

    @Autowired
    private MessageQueueProducer messageQueueProducer;
    @Autowired
    private RedisService redisService;
    @Autowired
    private UserService userService;

    @Override
    protected AccountRelationTypeEnum getRelationType() {

        return AccountRelationTypeEnum.USER_USER;
    }

    @Override
    protected AccountRelationStatusEnum getSubscribeStatus() {
        // 用户订阅时，设置为等待确认状态
        return AccountRelationStatusEnum.WAIT_CONFIRMED;
    }

    @Override
    protected boolean isAsyncDoAfterComplete() {

        return true;
    }

    @Override
    protected void doAfterComplete(Long id, String sourceAccount, String targetAccount, boolean subscribe) {
        if (subscribe) {
            // 推送被订阅用户消息红点提醒
            this.doNotifyRedPointByWebSocket(targetAccount);
            // 添加待审核用户到审核redis缓存列表
            this.addUser2WaitConfirmListCache(id, sourceAccount, targetAccount);
        }
    }

    /**
     * 走redis查询用户待审核好友申请列表数据
     *
     * @param account
     * @return
     */
    public List<WaitConfirmUserResponseVO> listWaitConformUsers(String account) {
        String cacheKey = RedisKeyEnum.WAIT_CONFIRM_USER_LIST_CACHE.getKey(account);
        // 按照申请时间倒序查询，一次拉去所有待审核（实际使用场景一般待审核不会很多，没必要分页查询）
        Set<String> waitConfirmUsers = redisService.zreverseRange(cacheKey, 0, Long.MAX_VALUE);
        if (CollectionUtils.isEmpty(waitConfirmUsers)) {
            return Collections.emptyList();
        }
        List<WaitConfirmRelationBaseDTO> relations =
                waitConfirmUsers.stream()
                .map(cache -> JsonUtil.fromJson(cache, WaitConfirmRelationBaseDTO.class))
                .collect(Collectors.toList());
        List<String> sourceAccounts = relations.stream().map(WaitConfirmRelationBaseDTO::getSourceAccount).collect(Collectors.toList());
        // 走缓存批量查询待审核用户详情信息
        Map<String, UserBaseResponseInfoVO> waitConfirmUserMap = userService.batchGetUserInfoFromCache(sourceAccounts);
        return relations.stream().map(r ->
                new WaitConfirmUserResponseVO(r.getId(), waitConfirmUserMap.get(r.getSourceAccount())))
                .collect(Collectors.toList());
    }

    /**
     * 添加sourceAccount到targetAccount却确认redis缓存列表
     *
     * @param relationId 关系id，用于后续审核通过/拒绝
     * @param sourceAccount
     * @param targetAccount
     */
    private void addUser2WaitConfirmListCache(Long relationId, String sourceAccount, String targetAccount) {

        /**
         * 构造缓存value对象
         */
        WaitConfirmRelationBaseDTO cacheValueObj = this.buildWaitConfirmRelationBaseDTO(relationId, sourceAccount, targetAccount);

        /**
         * 这里我们完全依赖redis，暂不考虑缓存失效场景，redis使用永久有效
         */
        String cacheKey = RedisKeyEnum.WAIT_CONFIRM_USER_LIST_CACHE.getKey(targetAccount);
        redisService.zadd(cacheKey, JsonUtil.toJsonString(cacheValueObj), DateUtils.getCurrentTimeMillis(),
                          RedisKeyEnum.WAIT_CONFIRM_USER_LIST_CACHE.getExpireTime());
    }

    private WaitConfirmRelationBaseDTO buildWaitConfirmRelationBaseDTO(Long relationId, String sourceAccount, String targetAccount) {
        return  WaitConfirmRelationBaseDTO.builder()
                .id(relationId)
                .sourceAccount(sourceAccount)
                .targetAccount(targetAccount).build();

    }

    /**
     * 删除targetAccount待审核缓存中的sourceAccount信息
     *
     * @param relationId 关系id
     * @param sourceAccount
     * @param targetAccount
     */
    private void removeUser2WaitConfirmListCache(Long relationId, String sourceAccount, String targetAccount) {
        /**
         * 这里我们完全依赖redis，暂不考虑缓存失效场景，redis使用永久有效
         */
        WaitConfirmRelationBaseDTO cacheValueObj = this.buildWaitConfirmRelationBaseDTO(relationId, sourceAccount, targetAccount);
        String cacheKey = RedisKeyEnum.WAIT_CONFIRM_USER_LIST_CACHE.getKey(targetAccount);
        redisService.zremove(cacheKey, JsonUtil.toJsonString(cacheValueObj));
    }

    /**
     * 确认订阅关系
     *
     * @param confirmAccount 确认账号
     * @param relationId 确认关系ID
     * @return
     */
    public Boolean confirmSubscribe(String confirmAccount, Long relationId) {
        AccountRelationEntity entity = super.getRelationEntityById(relationId);
        Assert.notNull(entity, "关系不存在");
        Assert.isTrue(entity.getTargetAccount().equals(confirmAccount), "无权限！");
        entity.setStatus(AccountRelationStatusEnum.CONFIRMED.getStatus());
        entity.setUpdateDate(new Date());
        // 更新关系
        super.updateAccountRelationEntity(entity);
        String sourceAccount = entity.getSourceAccount();
        String targetAccount = entity.getTargetAccount();
        // 添加群聊到用户账号关系列表
        super.init(targetAccount, sourceAccount);
        super.addTargetAccountRelationListCache(targetAccount, sourceAccount);
        super.init(sourceAccount, targetAccount);
        super.addTargetAccountRelationListCache(sourceAccount, targetAccount);
        // 好友申请通过，后续不需要在审核，删除redis缓存
        this.removeUser2WaitConfirmListCache(entity.getId(), sourceAccount, targetAccount);
        // 好友申请通过，刷新用户最新对话列表缓存(U1->U2, 将U2刷新到U1最新对话列表，同时需要将U1刷入到U2的最新对话列表中)
        super.addTargetAccount2SourceLastChattingList(sourceAccount, targetAccount);
        super.addTargetAccount2SourceLastChattingList(targetAccount, sourceAccount);
        return true;
    }

    /**
     * 拒绝订阅关系
     *
     * @param confirmAccount 拒绝账号
     * @param relationId 确认关系ID
     * @return
     */
    public Boolean rejectSubscribe(String confirmAccount, Long relationId) {

        AccountRelationEntity entity = super.getRelationEntityById(relationId);
        Assert.notNull(entity, "关系不存在");
        Assert.isTrue(entity.getTargetAccount().equals(confirmAccount), "无权限！");
        entity.setStatus(AccountRelationStatusEnum.REJECTED.getStatus());
        entity.setUpdateDate(new Date());
        // 更新关系
        super.updateAccountRelationEntity(entity);
        // 好友申请被拒绝，删除redis缓存
        this.removeUser2WaitConfirmListCache(entity.getId(), entity.getSourceAccount(), entity.getTargetAccount());
        return true;
    }

    /**
     * 基于ws，为targetAccount推送订阅消息红点提醒
     *
     */
    private void doNotifyRedPointByWebSocket(String targetAccount) {
        MessageNotifyVO messageBase = new MessageNotifyVO();
        messageBase.setReceiverId(targetAccount);
        messageBase.setType(ChatMessageTypeEnum.APPLY.getType());
        messageQueueProducer.broadSend(MessageBroadChannelEnum.QUEUE_CHAT_NOTIFY, messageBase);
    }
}
